package priv.lirenhe.dissertation.component.search_engine.search_index;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.StaleReaderException;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;

import com.chenlb.mmseg4j.analysis.MMSegAnalyzer;

public class Indexer {
	private Directory directory ;
	private static int closeNum ;
	private static Map<Directory,IndexReader> map_indexReader = new HashMap<Directory,IndexReader>();
	private static Map<Directory,IndexSearcher> map_indexSearcher = new HashMap<Directory,IndexSearcher>();
	private static Map<String,Directory> indexPath_Dir = new HashMap<String,Directory>();
	
	public Indexer(String indexPath){
		System.out.println("IndexUtil 构造方法初始化！");
		boolean emptyButNotEqual = true;
		try{
			if( !indexPath_Dir.isEmpty()){
				Set<String> set_indexPath = indexPath_Dir.keySet();
				for(String str : set_indexPath){
					if(str.equals(indexPath)){
						directory = indexPath_Dir.get(str);
						emptyButNotEqual = false;
						break;
					}
				}
			}else{
				directory = FSDirectory.open(new File(indexPath));
				indexPath_Dir.put(indexPath, directory);
			}
			if(emptyButNotEqual){
				directory = FSDirectory.open(new File(indexPath));
				indexPath_Dir.put(indexPath, directory);
			}
//			map_indexReader.put(directory,  IndexReader.open(directory,false));
		}catch(IOException ioe){
			ioe.printStackTrace();
		}
	}
	
	/**
	 * 创建索引
	 * @param documents
	 */
	public void createIndex(List<Document> documents){
		System.out.println("创建索引！");
		
		IndexWriter indexWriter = null;
		try {
			indexWriter = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35, new MMSegAnalyzer()));//StandardAnalyzer(Version.LUCENE_35)
			System.out.println("indexWriter="+indexWriter);
//			if(indexWriter != null){
//				indexWriter.deleteAll();
//			}
			Document docment = null;
			for(Document document:documents){
				indexWriter.addDocument(document);
			}
			closeNum++;
			
		} catch (CorruptIndexException e1) {
			e1.printStackTrace();
		} catch (LockObtainFailedException e1) {
			e1.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			if(indexWriter != null){
				try {
					if(closeNum > 5){
						indexWriter.close(true);
						closeNum = 0;
					}else{
						indexWriter.close();
					}
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	/**
	 * 创建文档
	 * @param list_list_OfField
	 * @return
	 */
	public List<Document> createDocuments(List<List<Field>> list_list_OfField){
		List<Document> documents = null;
		try{
			if(list_list_OfField != null){
				documents = new ArrayList<Document>();
				for(List<Field> list_field:list_list_OfField){
					Document document = new Document();
					for(Field field:list_field){
						document.add(field);
					}
					documents.add(document);
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return documents;
	}
	
	/**
	 * Forces merging of all segments that have deleted documents.
	 * this method first flushes a new segment (if there are indexed documents), and applies all buffered deletes. 
	 * @param directory
	 */
	public void forceDeleteIndexWriter(){
		IndexWriter indexWriter = null;
		try {
			indexWriter = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
			indexWriter.forceMergeDeletes();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(indexWriter != null){
				try {
					indexWriter.close(true);
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		
	}
	/**
	 * 不删索引Undeletes all documents currently marked as deleted in this index. 
	 */
	public void undeleteIndexReader(){
		
		try {
			this.getNewIndexReader().undeleteAll();
		} catch (StaleReaderException e) {
			e.printStackTrace();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	/**
	 * 关闭indexReader：Closes files associated with this index. 
	 * Also saves any new deletions to disk. No other methods should be called after this has been called.
	 */
	public void closeIndexReader(){
		
		try {
			map_indexReader.get(directory).close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
//	public void closeIndexWriter(){
//		
//		try {
//			map_indexWriter.get(directory).close();
//		} catch (CorruptIndexException e) {
//			e.printStackTrace();
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}
	
	public void closeIndexSearcher(){
		
		try {
			map_indexSearcher.get(directory).close();
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 
	 */
	public void mergeIndex(int num){
		
		IndexWriter indexWriter = null;
		try {
			if(directory != null){
				indexWriter = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
				indexWriter.forceMerge(num);
			}
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (LockObtainFailedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			if(indexWriter != null){
				try {
					indexWriter.close(true);
				} catch (CorruptIndexException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
	/**
	 * 更新index
	 * @param document
	 * @param term
	 */
	public void updateIndex(Document document,Term term){
		
		IndexWriter indexWriter = null;
		try {
			indexWriter = new IndexWriter(directory,new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));
			indexWriter.updateDocument(term, document);
		} catch (CorruptIndexException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				if(indexWriter != null){
					if(closeNum > 5){
						indexWriter.close(true);
						closeNum = 0;
					}else{
						indexWriter.close();
					}
				}
			} catch (CorruptIndexException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	
	/**
	 * 查询基本的数据
	 * @return
	 */
	public Map<String,String> queryIndex(){
		
		IndexReader indexReader = null;
		Map<String,String> map_queryData = null;
		indexReader = this.getNewIndexReader();
		map_queryData.put("numDocs", indexReader.numDocs()+"");
		map_queryData.put("maxDoc",indexReader.maxDoc()+"");
		map_queryData.put("numDeletedDocs", indexReader.numDeletedDocs()+"");
		
		return map_queryData;
	}
	
	private ScoreDoc getLastScoreDoc(int pageIndex,int pageSize,Query query,IndexSearcher searcher){
		ScoreDoc scoreDoc = null;
		try {
			if(pageIndex == 1 ){
				return null;
			}
			int lastPageNum = (pageIndex - 1) * pageSize;
			TopDocs topDocs = searcher.search(query, lastPageNum);
			scoreDoc = topDocs.scoreDocs[lastPageNum - 1];
		} catch (IOException e) {
			e.printStackTrace();
		}
		return scoreDoc;
	}
	/**
	 * 查询ByQueryParser
	 * @param query
	 * @param num
	 * @return
	 */
	public List<Document> searchByQueryParser(Query query,int pageIndex,int pageSize){
		
		IndexSearcher indexSearcher = null;
		LinkedList<Document> list_OfDocuments = null;
		try {
			indexSearcher = this.getSearcher();
			ScoreDoc lastScoreDoc = this.getLastScoreDoc(pageIndex, pageSize, query, indexSearcher);
			TopDocs topDocs = indexSearcher.searchAfter(lastScoreDoc, query, pageSize);
			
			if(topDocs != null && topDocs.scoreDocs.length > 0){
				list_OfDocuments = new LinkedList<Document>();
				for(ScoreDoc scoreDoc:topDocs.scoreDocs){
					Document doc = indexSearcher.doc(scoreDoc.doc);
					list_OfDocuments.add(doc);
					System.out.print(doc.get("webPageRealurl")+"===>");
					System.out.println(doc.get("webPageTitle"));
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return list_OfDocuments;
	}
	
	/**
	 * Creates a searcher searching the provided index. 
	 * @return
	 */
	public synchronized IndexSearcher getSearcher(){
		IndexSearcher oldIndexSearcher = null;
		
		try{
			if(!map_indexSearcher.isEmpty()){
				oldIndexSearcher = map_indexSearcher.get(directory);
			}else{
				 map_indexSearcher.put(directory, new IndexSearcher(this.getNewIndexReader()));
				 return map_indexSearcher.get(directory);
			}
			
			if(oldIndexSearcher != null){
				if(!oldIndexSearcher.getIndexReader().isCurrent()){
					map_indexSearcher.put(directory, new IndexSearcher(this.getNewIndexReader()));
					return map_indexSearcher.get(directory);
				}
			}else{
				map_indexSearcher.put(directory, new IndexSearcher(this.getNewIndexReader()));
				return map_indexSearcher.get(directory);
			}
		}catch( IOException e){
			e.printStackTrace();
		}
		return map_indexSearcher.get(directory);
	}
	
	/**
	 * 得到新的IndexReader
	 * @return
	 */
	public synchronized IndexReader getNewIndexReader(){
		System.out.println("getNewIndexReader 获得indexReader");
		
		IndexReader oldIndexReader = null;
		IndexReader newIndexReader = null;
		try {
			if(!map_indexReader.isEmpty()){
				System.out.println("!map_indexReader.isEmpty()");
				oldIndexReader = map_indexReader.get(directory);
			}else{
				System.out.println("map_indexReader.isEmpty()");
				map_indexReader.put(directory, IndexReader.open(directory,false));
				return map_indexReader.get(directory);
			}
			
			if(oldIndexReader != null){
				newIndexReader = IndexReader.openIfChanged(oldIndexReader);
				if(newIndexReader != null){
					System.out.println("openIfChanged");
					oldIndexReader.close();
					map_indexReader.put(directory, newIndexReader);
				}
			}else{
				map_indexReader.put(directory, IndexReader.open(directory,false));
				return map_indexReader.get(directory);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return map_indexReader.get(directory);
	}
	
	
	
	
}
